#!/bin/bash

# 日志中需要检查的关键内容
LOG_KEYWORD="Server ready"
# Docker 运行命令（如果容器未运行）
# 最大重试次数
MAX_ATTEMPTS=3
# 日志检查超时时间（秒）
LOG_TIMEOUT=600
# 日志文件路径
LOG_FILE="/sumz/letsencrypt_manager_$(date +%Y%m%d).log"
# 时间戳格式
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
# 证书检查的域名
CERT_DOMAIN="wangwuli.com"
# 子域名
SUB_DOMAINS="wildcard"
# 监听的域名
CHKCK_DOMAIN="www.wangwuli.com"
# 监听域名端口
CHKCK_DOMAIN_PORT=80
# 完整域名
FULL_DOMAIN="$SUB_DOMAINS.$CERT_DOMAIN"
# 证书过期预警阈值（天）
EXPIRY_THRESHOLD_DAYS=7
# 证书续期阈值（天）
CERT_RENEWAL_THRESHOLD_DAYS=30
# 容器名称
CONTAINER_NAME="$FULL_DOMAIN"
# 本地路径， 需求证书的读取位置
LOCAL_PATH="/etc/nginx/key/$CONTAINER_NAME"
# 启动命令
RUN_COMMAND="/usr/bin/docker run \
  -it -d \
  --cap-add=NET_ADMIN \
  --name=$CONTAINER_NAME \
  -v $LOCAL_PATH:/config/dns-conf/:rw \
  -e PGID=1000 \
  -e PUID=1000 \
  -e EMAIL=wangwuli@sumztech.com \
  -e URL=$CERT_DOMAIN \
  -e SUBDOMAINS=$SUB_DOMAINS \
  -e DHLEVEL=2048 \
  -e VALIDATION=dns \
  -e DNSPLUGIN=aliyun \
  -e TZ=Asia/Shanghai \
  www.wangwuli.com:100/sumzbase/linuxserver/swag"


# 确保日志目录存在
mkdir -p "$(dirname "$LOG_FILE")"
# 确保本地key路径存在
mkdir -p $LOCAL_PATH

# 日志记录函数
log() {
    echo "[$TIMESTAMP] $1" | tee -a  "$LOG_FILE"
}

# 检查在线证书过期时间并决定是否需要续期
check_cert_expiry_online() {
    log "开始检查域名 $CHKCK_DOMAIN 的在线证书过期时间..."
    
    # 使用 openssl s_client 获取证书
    CERT_INFO=$(echo | openssl s_client -connect "$CHKCK_DOMAIN:$CHKCK_DOMAIN_PORT" -servername "$CHKCK_DOMAIN" 2>/dev/null | openssl x509 -noout -enddate)
    if [ $? -ne 0 ] || [ -z "$CERT_INFO" ]; then
        log "错误：无法获取 $CHKCK_DOMAIN 的证书信息，请检查域名或网络，将继续执行续期操作"
        return 1
    fi

    # 提取过期时间
    EXPIRY_DATE=$(echo "$CERT_INFO" | cut -d= -f2)
    if [ -z "$EXPIRY_DATE" ]; then
        log "错误：无法解析 $CHKCK_DOMAIN 的证书过期时间，将继续执行续期操作"
        return 1
    fi

    # 将过期时间和当前时间转换为时间戳
    EXPIRY_TIMESTAMP=$(date -d "$EXPIRY_DATE" +%s 2>/dev/null)
    CURRENT_TIMESTAMP=$(date +%s)
    if [ -z "$EXPIRY_TIMESTAMP" ]; then
        log "错误：无法将证书过期时间转换为时间戳，将继续执行续期操作"
        return 1
    fi

    # 计算剩余天数
    DAYS_LEFT=$(( (EXPIRY_TIMESTAMP - CURRENT_TIMESTAMP) / 86400 ))

    log "证书 $CERT_DOMAIN 过期时间: $EXPIRY_DATE"
    log "证书剩余有效天数: $DAYS_LEFT 天"

    # 判断证书状态
    if [ $DAYS_LEFT -lt 0 ]; then
        log "警告：证书 $CERT_DOMAIN 已过期，需要续期"
        return 1
    elif [ $DAYS_LEFT -le $CERT_RENEWAL_THRESHOLD_DAYS ]; then
        log "证书 $CERT_DOMAIN 剩余 $DAYS_LEFT 天（小于等于续期阈值 $CERT_RENEWAL_THRESHOLD_DAYS 天），需要续期"
        return 1
    else
        log "证书 $CERT_DOMAIN 有效（剩余 $DAYS_LEFT 天，大于续期阈值 $CERT_RENEWAL_THRESHOLD_DAYS 天），无需续期"
        return 0
    fi
}

# 检查容器状态并执行相应操作
check_and_manage_container() {
    log "检查容器 $CONTAINER_NAME 状态..."
    if [ $(/usr/bin/docker ps -a -q -f name=$CONTAINER_NAME) ]; then
        log "容器 $CONTAINER_NAME 存在，执行重启..."
        /usr/bin/docker exec $CONTAINER_NAME bash -c "rm -f /etc/letsencrypt/archive/$CERT_DOMAIN/*.pem"
        if /usr/bin/docker restart $CONTAINER_NAME; then
            log "容器 $CONTAINER_NAME 重启成功"
        else
            log "容器 $CONTAINER_NAME 重启失败"
            return 1
        fi
    else
        log "容器 $CONTAINER_NAME 未运行，执行启动..."
        if $RUN_COMMAND; then
            log "容器 $CONTAINER_NAME 启动成功"
        else
            log "容器 $CONTAINER_NAME 启动失败"
            return 1
        fi
    fi
    return 0
}

# 检查容器日志
check_container_log() {
    log "开始检查容器 $CONTAINER_NAME 的日志，查找关键字: $LOG_KEYWORD"
    # 等待一段时间并检查日志
    timeout $LOG_TIMEOUT /usr/bin/docker logs $CONTAINER_NAME 2>&1 | grep -q "$LOG_KEYWORD"
    if [ $? -eq 0 ]; then
        log "日志中找到关键字: $LOG_KEYWORD，容器运行正常"
        return 0
    else
        log "未找到关键字: $LOG_KEYWORD"
        return 1
    fi
}

# 主逻辑
log "开始执行容器管理脚本..."

# 先检查证书是否需要续期
if check_cert_expiry_online; then
    log "证书无需续期，脚本退出"
    exit 0
fi

# 如果证书需要续期，继续执行容器管理和证书生成
FAILURE_COUNT=0

while [ $FAILURE_COUNT -lt $MAX_ATTEMPTS ]; do
    # 检查并管理容器（启动或重启）
    if check_and_manage_container; then
        # 等待容器稳定
        sleep 30
        # 检查日志
        if check_container_log; then
            log "容器运行成功，退出重试循环"
            break
        else
            ((FAILURE_COUNT++))
            log "第 $FAILURE_COUNT 次失败，剩余尝试次数: $((MAX_ATTEMPTS - FAILURE_COUNT))"
        fi
    else
        ((FAILURE_COUNT++))
        log "第 $FAILURE_COUNT 次失败（容器启动/重启失败），剩余尝试次数: $((MAX_ATTEMPTS - FAILURE_COUNT))"
    fi

    # 检查是否达到最大失败次数
    if [ $FAILURE_COUNT -eq $MAX_ATTEMPTS ]; then
        log "连续 $MAX_ATTEMPTS 次失败，放弃并退出"
        exit 1
    fi
done

# 继续执行其他 shell 命令
log "容器运行正常，证书已经生成，继续执行后续命令..."

log "执行证书拷贝命令..."
/usr/bin/docker exec "$CONTAINER_NAME" bash -c "cp -L /etc/letsencrypt/live/$CERT_DOMAIN/*.pem /config/dns-conf/" >> "$LOG_FILE" 2>&1
if [ $? -eq 0 ]; then
    log "证书拷贝成功"
else
    PEM_COUNT=$(docker exec "$CONTAINER_NAME" bash -c "ls /etc/letsencrypt/live/$CERT_DOMAIN/*.pem 2>/dev/null | wc -l")
    if [ "$PEM_COUNT" -eq 0 ]; then
        log "证书拷贝失败,未生成新的证书"
    else
        log "证书拷贝失败,原因未知"
    fi
fi

log "执行 Nginx 重新加载配置..."
/usr/bin/systemctl restart nginx.service >> "$LOG_FILE" 2>&1
if [ $? -eq 0 ]; then
    log "Nginx 配置重新加载成功"
else
    log "Nginx 配置重新加载失败"
fi

log "所有操作完成"